// 自定义promise  
((window) => {


  // 定义状态值常量
  const PENDING = 'pending';
  const FULFILLED = 'fulfilled';
  const REJECTED = 'rejected';

  /**
   * 构造函数   @param 给参数命名的意思
   * @param  excutor 执行器函数
   */

  /* 
  promise对象内部要存储哪些信息?
    1. 状态: pending/fulfilled/rejected  ==> state
    2. 结果数据: undefined/value/reason  ==> data
    3. 保存待处理回调的数组: [{resolved () {}, rejected () {}}, {resolved () {}, rejected () {}}] => callbacks
 
    在构造函数中, 会立即同步调用执行器函数, 并传入resolve和reject 两个函数

    resolve函数
      参数: value
      作用: 将promise的状态改为resolved, 将value保存到data
    reject函数
      参数: reason
      作用: 将promise的状态改为rejected, 将reason保存到data
  */

  function Promise (excutor) {
    // 初始化三个属性
    // 1. 状态 pending/fulfilled/rejected  ==> state
    this.state = PENDING
    // 2. 结果数据  undefined/value/reason  ==> data
    this.data = undefined
    // 3. 保存待处理回调的数组: [{resolved () {}, rejected () {}}, {resolved () {}, rejected () {}}] => callbacks
    this.callbacks = [];
    const self = this;


    /* 
    resolve函数
    参数: value
    作用: 将promise的状态改为resolved, 将value保存到data
   */
    function resolve (value) {
      console.log(1);
      // 只有当前状态不为pendding, 才向下处理
      if (self.state !== PENDING) return
      // 改状态为成功的
      self.state = FULFILLED
      // 保存数据
      self.data = value
      // 异步执行callbacks中所有成功的回调
      // 我们没办法直接向微队列中添加回调 => 只能用宏队列了 setTimeout
      setTimeout(() => {
        self.callbacks.forEach(callbackObj => callbackObj.resolved(value))
      }, 0)
    }

    /* 
    reject函数
    参数: reason
    作用: 将promise的状态改为rejected, 将reason保存到data
    */
    function reject (reason) {
      // 只有当前状态为pendding, 才向下处理
      if (self.state !== PENDING) return
      // 改状态为失败的
      self.state = REJECTED
      // 保存数据
      self.data = reason
      // 异步执行callbacks中所有成功的回调
      // 我们没办法直接向微队列中添加回调 => 只能用宏队列了 setTimeout
      setTimeout(() => {
        self.callbacks.forEach(callbackObj => callbackObj.rejected(reason))
      }, 0)
    }
    // 捕获执行器抛出的错误
    try {
      /*  在构造函数中, 会立即同步调用执行器函数, 并传入resolve和reject 两个函数 */
      excutor(resolve, reject);
    } catch (error) {
      // 将当前promise变为rejected, reason为error
      reject(error)
    }
  }

  /**
   * 指定成功和失败的回调, 并返回一个新的promise  都放到Promise的原型对象上
   * @param {*} onResolved 成功的回调 => 用于得到成功的value
   * @param {*} onRejected 失败的回调 => 用于得到失败的reason
   */

  /* 
 then返回的promise的结果由什么决定
  简单表达: 由then指定的回调执行的结果决定
    返回promise  ==> 得到并改为它的状态
    返回非promise  ==> 变为成功状态
    抛出错误   ==> try---catch  => 变为失败状态
*/

  // 成功的回调
  Promise.prototype.then = function (onResolved, onRejected) {
    const self = this
    // 判断onResolved 和 onRejected类型
    // 如果onResolved不是函数, 指定一个默认函数, 向下传递value
    onResolved = typeof onResolved === 'function' ? onResolved : value => value
    // 如果onRejected不是函数, 指定一个默认函数, 向下传递reason
    onRejected = typeof onRejected === 'function' ? onRejected : reason => { throw reason }


    // 返回一个新的promise
    return new Promise((resolve, reject) => {

      /**
       * 调用指定成功/失败的回调函数, 根据执行结果更新返回的promies的状态
       * @param {*} callback 
       */
      function handle (callback) {
        try {
          const result = callback(self.data)
          if (result instanceof Promise) { // 情况1: 返回promise  ==> 得到并改为它的状态
            result.then(
              value => resolve(value),
              reason => reject(reason)
            )
          } else { // 情况2: 返回非promise  ==> 变为成功状态
            resolve(result)
          }
        } catch (error) { // 情况3: 抛出错误   ==> try---catch  => 变为失败状态
          reject(error)
        }
      }


      // 如果当前是成功的, 异步执行onResolved
      if (self.state === FULFILLED) { // 如果当前promise是成功的, 异步执行成功的回调
        setTimeout(() => {
         handle(onResolved)
        }, 0)
        // 如果当前promise是失败的, 异步执行失败的回调 
      } else if (self.state === REJECTED) { 
        setTimeout(() => {
          handle(onRejected)
        }, 0)
      } else { 
        // 如果当前promise是pending, 保存成功和失败的回调
        self.callbacks.push({
          resolved: () => handle(onResolved),
          rejected: ()=> handle(onRejected)
        })
      }
    })
  }

   /**
   * 指定失败的回调, 并返回一个新的promise
   * 本质是then方法的语法糖(简洁语法)
   * then(value => value, onRejected)
   * @param {*} onRejected 失败的回调 => 用于得到失败的reason
   */
  Promise.prototype.catch = function (onRejected) {
    return this.then(value => value, onRejected)
   }

  /**
  *  返回一个成功的promise, value为指定的value
  *  @param {*} value  可能是非promise, 也可能是promise
  */
  Promise.resolve = function (value) {
    console.log(1);
    return new Promise((resolve, reject) => {
      if (value instanceof Promise) {
        value.then(
          value => resolve(value),
          reason => reject(reason)
        )
      } else {
        resolve(value)
      }
    })
  }

  /**
   *  返回一个失败的promise, reason为指定的reason
   * @param {*} reason
   */
  Promise.reject = function (reason) {
    return new Promise((resolve, reject) => {
      reject(reason)
    })
  }

  /**
   * 返回一个promise, 如果promises都成功, 才成功   成功的value为所有value组成的数组, 只要有一个失败, 那它就失败了
   * @param {*} promises  
   */
  Promise.all = function (promises) {
    // 保存所有成功Promise的value数组
    const vaules = []
    // 成功的数量
    let resolveCount = 0

    // 返回一个prmise对象
    return new Promise((resolve,reject)=>{
      promises.forEach((p,ind)=>{
        p.then(
          value=>{
            // 保存当前成功的value
            values[ind] = value
            // 成功的数量+1
            resolveCount += 1
            // 如果当前是最后一个成功的 将返回promise的状态为成功
            if(resolveCount === promises.length){
              resolve(vaules)
            }
          },
          reason =>{
            // 只要有一个promise失败 当前返回的promise就直接失败
            reject(reason)
          }
        )
      })
    })
  }

  /**
 * 返回一个promise, 由第一个完成的promie来决定它的结果
 * @param {*} promises 
 */
  Promise.race = function (promises) {
    return new Promise((resolve,reject)=>{
      promises.forEach(p=>{
        p.then(
          value => resolve(value),
          reason => reject(reason)
        )
      })
    })
  }

  /**
   * 返回一个promise, 当所有promise都完成时它就成功, value值为所有promise的value或reason组成的数组
   * @param {*} promises 
   */
  Promise.allSettled = function (promises) {
    // 保存所有完成Promise的value/reason 的数组
    const results = []
    // 完成的数量
    let settledCount = 0 

    // 返回的promise不会变为失败的 只会变为成功的 所有的都完成 就会成功  成功value是所有promise的value或reason组成的数组
    return new Promise(resolve=>{
      promises.forEach((p,ind)=>{
        p.then(
          value => {
            // 保存当前成功 value 和成功状态的对象
            results[ind] = { status : 'fulfilled' , value}
            settledCount++
            if(settledCount === promises.length) resolve(results)
          },
          reason => {
            // 保存当前失败的reason和失败状态的对象
            results[ind] = { status : 'rejected' , reason}
            settledCount ++
            if (settledCount===promises.length) {
              resolve(results)
            }
          }
        )
      })
    })

  }

  // 向外暴露自定义的Promise
  window.Promise = Promise
})(window)
